import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { JwtService } from '@nestjs/jwt';
import { Request as ExpressRequest } from 'express';
import { isEmpty } from 'lodash';

import { AUTHORIZE_KEY_METADATA, CURRENT_USER } from 'src/core/contants';
import { ApiException } from 'src/core/exceptions/api.exception';
import { RedisService } from 'src/shared/redis/redis.service';

@Injectable()
export class AuthGuard implements CanActivate {
  constructor(
    private reflector: Reflector,
    private jwtService: JwtService,
    private redisService: RedisService,
  ) {}

  async canActivate(context: ExecutionContext): Promise<boolean> {
    // 使用 @Authorize() 的直接放行
    const authorize = this.reflector.get<boolean>(AUTHORIZE_KEY_METADATA, context.getHandler());
    if (authorize) {
      return true;
    }

    const request = context.switchToHttp().getRequest<ExpressRequest>();
    const token = request.headers['authorization'].replace('Bearer ', '');

    // token 不通过
    if (isEmpty(token)) {
      throw new ApiException(11001);
    }

    try {
      // 挂在到请求上
      request[CURRENT_USER] = this.jwtService.verify(token);
    } catch (err) {
      throw new ApiException(11001);
    }

    // token 与 redis 保存的不一致
    const redisToken = await this.redisService.getRedisTokenById(request[CURRENT_USER].uid);
    if (token !== redisToken) {
      throw new ApiException(11002);
    }

    // pass
    return true;
  }
}
